package dao;

// 封装针对Problem的增删改查操作
// 1. 新增题目
// 2. 删除题目
// 3. 查询题目列表
// 4. 查询题目详情

import common.DBUtil;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class ProblemDao {
    // 新增题目
    public void insert(Problem problem) {
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            // 1. 和数据库建立连接
            connection = DBUtil.getConnection();
            // 2. 构造sql语句
            String sql = "insert into oj_table values(null,?,?,?,?,?)";
            statement = connection.prepareStatement(sql);
            statement.setString(1, problem.getTitle());
            statement.setString(2, problem.getLevel());
            statement.setString(3,problem.getDescription());
            statement.setString(4,problem.getTemplateCode());
            statement.setString(5,problem.getTestCode());
            // 3. 执行sql
            int ret = statement.executeUpdate(); // 表示影响的行数
            if(ret != 1) {
                System.out.println("题目新增失败！");
            } else {
                System.out.println("题目新增成功！");
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            // 为了保证关闭资源一定被执行到！
            DBUtil.close(connection,statement,null);
        }
    }

    // 删除题目
    public void delete(int id) {
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            // 1. 建立数据库连接
            connection = DBUtil.getConnection();
            // 2. 构造sql语句
            String sql = "delete from oj_table where id = ?";
            statement = connection.prepareStatement(sql);
            statement.setInt(1,id);
            // 3. 执行sql语句（判断）
            int ret = statement.executeUpdate();
            if(ret != 1) {
                System.out.println("删除题目失败！");
            } else {
                System.out.println("删除题目成功！");
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            // 关闭资源
            DBUtil.close(connection,statement,null);
        }
    }

    // 查询题目列表
    // 该操作是把当前题目列表中所有的题目都给查询出来
    // 但是如果数据库中的数据特别多，实现“分页查询”即可
    // 后台实现分页查询是很容易的：前端传过来一个当前的“页码”，根据页码算一下，依据 sql limit offset语句来计算出offset即可
    // 但是前端实现分页器稍微麻烦一些，所以此处暂时不考虑分页功能
    public List<Problem> selectAll() {
        // 作为返回值
        List<Problem> problems = new ArrayList<>();
        // 注意不进行全表查询!!
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            // 1. 和数据库建立连接
            connection = DBUtil.getConnection();
            // 2. 拼装sql语句
            String sql = "select id, title, level from oj_table";
            statement = connection.prepareStatement(sql);
            // 3. 执行sql语句
            // 注意查询操作这里是Query！
            // 并且注意返回值类型！！
            resultSet = statement.executeQuery();
            // 4. 遍历resultSet
            while (resultSet.next()) {
                // 获取到每一行数据，每一行都是一个Problem对象
                Problem problem = new Problem();
                problem.setId(resultSet.getInt("id"));
                problem.setTitle(resultSet.getString("title"));
                problem.setLevel(resultSet.getString("level"));
                // 拿到之后将数据加入到链表中
                problems.add(problem);
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            DBUtil.close(connection,statement,resultSet);
        }
        return problems;
    }

    // 查询题目详情
    public Problem selectOne(int id) {
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            // 1. 建立数据库连接
            connection = DBUtil.getConnection();
            // 2. 拼接SQL
            String sql = "select * from oj_table where id = ?";
            statement = connection.prepareStatement(sql);
            statement.setInt(1,id);
            // 3. 执行sql
            resultSet = statement.executeQuery();
            // 4. 遍历结果集:因为id是主键，所以一定是唯一的一条结果，要么存在要么不存在
            if(resultSet.next()) {
                Problem problem = new Problem();
                problem.setId(resultSet.getInt("id"));
                problem.setTitle(resultSet.getString("title"));
                problem.setLevel(resultSet.getString("level"));
                problem.setDescription(resultSet.getString("description"));
                problem.setTemplateCode(resultSet.getString("templateCode"));
                problem.setTestCode(resultSet.getString("testCode"));
                return problem;
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            // 一定要进行资源关闭
            DBUtil.close(connection,statement,resultSet);
        }
        return null;
    }



    // 进行测试：只是简单的测试 —— “冒烟测试”，“单元测试”

    // 测试插入
    private static void testInsert() {
        ProblemDao problemDao = new ProblemDao();
        // 新建一个实例，也就是题目数据
        Problem problem = new Problem();
        problem.setTitle("两数之和");
        problem.setLevel("简单");
        problem.setDescription("给定一个整数数组 nums 和一个整数目标值 target，请你在该数组中找出 和为目标值 target  的那 两个 整数，并返回它们的数组下标。\n" +
                "\n" +
                "你可以假设每种输入只会对应一个答案。但是，数组中同一个元素在答案里不能重复出现。\n" +
                "\n" +
                "你可以按任意顺序返回答案。\n" +
                "\n" +
                " \n" +
                "\n" +
                "示例 1：\n" +
                "\n" +
                "输入：nums = [2,7,11,15], target = 9\n" +
                "输出：[0,1]\n" +
                "解释：因为 nums[0] + nums[1] == 9 ，返回 [0, 1] 。\n" +
                "示例 2：\n" +
                "\n" +
                "输入：nums = [3,2,4], target = 6\n" +
                "输出：[1,2]\n" +
                "示例 3：\n" +
                "\n" +
                "输入：nums = [3,3], target = 6\n" +
                "输出：[0,1]\n" +
                " \n" +
                "\n" +
                "提示：\n" +
                "\n" +
                "2 <= nums.length <= 104\n" +
                "-109 <= nums[i] <= 109\n" +
                "-109 <= target <= 109\n" +
                "只会存在一个有效答案\n" +
                " \n" +
                "\n" +
                "进阶：你可以想出一个时间复杂度小于 O(n2) 的算法吗？\n" +
                "\n" +
                "来源：力扣（LeetCode）\n" +
                "链接：https://leetcode.cn/problems/two-sum\n" +
                "著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。");
        problem.setTemplateCode("class Solution {\n" +
                "    public int[] twoSum(int[] nums, int target) {\n" +
                "\n" +
                "    }\n" +
                "}");

        // 测试用例的代码是最难搞的！！
        problem.setTestCode("// main方法中的内容就相当于是测试用例的代码,到时候与用户提交的核心代码进行拼接就行\n" +
                "    public static void main(String[] args) {\n" +
                "        Solution solution = new Solution();\n" +
                "        // 测试用例可以参考详情页的输入输出测试\n" +
                "        // testCase1\n" +
                "        int[] nums = {2,7,11,15};\n" +
                "        int target = 9;\n" +
                "        int[] result = solution.twoSum(nums,target);\n" +
                "        // 检测运行结果，看与预期是否相符\n" +
                "        if(result.length==2 && result[0]==0 && result[1]==1) {\n" +
                "            System.out.println(\"testCase1 OK\");\n" +
                "        } else {\n" +
                "            System.out.println(\"testCase1 failed\");\n" +
                "        }\n" +
                "        // testCase2\n" +
                "        int[] nums2 = {3,2,4};\n" +
                "        int target2 = 6;\n" +
                "        int[] result2 = solution.twoSum(nums2,target2);\n" +
                "        // 检测运行结果，看与预期是否相符\n" +
                "        if(result2.length==2 && result2[0]==1 && result2[1]==2) {\n" +
                "            System.out.println(\"testCase2 OK\");\n" +
                "        } else {\n" +
                "            System.out.println(\"testCase2 failed\");\n" +
                "        }\n" +
                "        // testCase3\n" +
                "        int[] nums3 = {3,3};\n" +
                "        int target3 = 6;\n" +
                "        int[] result3 = solution.twoSum(nums3,target3);\n" +
                "        // 检测运行结果，看与预期是否相符\n" +
                "        if(result3.length==2 && result3[0]==0 && result3[1]==1) {\n" +
                "            System.out.println(\"testCase3 OK\");\n" +
                "        } else {\n" +
                "            System.out.println(\"testCase3 failed\");\n" +
                "        }\n" +
                "    }");
        problemDao.insert(problem);
    }

    // 测试查找列表
    private static void testSelectAll() {
        ProblemDao problemDao = new ProblemDao();
        List<Problem> problems = problemDao.selectAll();
        // 因为在Problem类中重写了toString方法，所以这里可以直接使用名字打印
        System.out.println(problems);
    }

    // 测试查找详情页
    private static void testSelectOne(int id) {
        ProblemDao problemDao = new ProblemDao();
        Problem problem = problemDao.selectOne(id);
        System.out.println(problem);
    }

    // 测试删除
    private static void testDelete(int id) {
        ProblemDao problemDao = new ProblemDao();
        problemDao.delete(id);
    }

    public static void main(String[] args) {
         testInsert(); // 测试插入
        // testSelectAll(); // 测试查找列表
        // testSelectOne(1);
        // testDelete(3);
    }
}
